package robocup.component.infotypes;

import java.util.LinkedList;

import robocup.component.speechacts.coachlanguage.AdviceMessage;
import robocup.component.speechacts.coachlanguage.DefineMessage;
import robocup.component.speechacts.coachlanguage.DeleteMessage;
import robocup.component.speechacts.coachlanguage.InfoMessage;
import robocup.component.speechacts.coachlanguage.MetaMessage;
import robocup.component.speechacts.coachlanguage.RuleMessage;
import robocup.component.speechacts.coachlanguage.TypeConstants;

/**
 * This class represents a message received from the coach. Because of the
 * complexity of the clang, there a different message types (freeform, rule,
 * advice, info, meta and delete).<br>
 * <br>
 * This info-type is used in two ways: First, it captures the messages received
 * by the players from the coach. Second, it can be translated into a string
 * with correct syntax, such that this can be sent via the server to the agents,
 * what corresponds more to an <b>action</b>.
 */
public class CoachSayInfo
    extends AuralInfo {

  /**
   * The type of the message. One of INIT, FREEFORM, DEFINE, RULE, ADVICE, INFO,
   * META or DELETE. This defines, which of the messages that can be contained,
   * is available in the given object.
   */
  private TypeConstants.MESSAGETYPE messageType     = TypeConstants.MESSAGETYPE.INIT;

  /**
   * The freeform message-string.
   */
  private String                    freeformMessage = "";

  /**
   * The rule-message.
   */
  private RuleMessage               ruleMessage     = null;

  /**
   * The advice message.
   */
  private AdviceMessage             adviceMessage   = null;

  /**
   * The info message.
   */
  private InfoMessage               infoMessage     = null;

  /**
   * The meta message.
   */
  private MetaMessage               metaMessage     = null;

  /**
   * The delete message.
   */
  private DeleteMessage             deleteMessage   = null;

  /**
   * The list of define-messages.
   */
  private LinkedList<DefineMessage> defineList      = new LinkedList<DefineMessage>();

  /**
   * Constructs an info-object for a heared message from the coach. This
   * includes CLANG as well as freeform messages - types are defined for
   * checking what was heared.
   * 
   * @param iCycle -
   *          when was it heared
   */
  public CoachSayInfo(
      final int iCycle) {

    super(iCycle);
    this.infoType = Info.TYPE_AURAL_CSI;
  }

  /**
   * @return Returns the message type of that info.
   */
  public TypeConstants.MESSAGETYPE getMessageType() {

    return this.messageType;
  }

  /**
   * Sets the message type for that info.
   * 
   * @param messageType -
   *          the new message-type.
   */
  public void setMessageType(final TypeConstants.MESSAGETYPE messageType) {

    this.messageType = messageType;
  }

  /**
   * @return Returns the rule-message.
   */
  public RuleMessage getRuleMessage() {

    return this.ruleMessage;
  }

  /**
   * Sets the rule-message for that info.
   * 
   * @param ruleMessage -
   *          the new rule-message.
   */
  public void setRuleMessage(final RuleMessage ruleMessage) {

    this.ruleMessage = ruleMessage;
    this.messageType = TypeConstants.MESSAGETYPE.RULE;
  }

  /**
   * @return Returns the freeform message string.
   */
  public String getFreeformMessage() {

    return this.freeformMessage;
  }

  /**
   * Sets a freeform string to this info.
   * 
   * @param freeformMessage -
   *          the new freeform message
   */
  public void setFreeformMessage(String freeformMessage) {

    if (freeformMessage.startsWith("\"")) {
      freeformMessage = freeformMessage.substring(1,
          freeformMessage.length() - 1);
    }
    this.freeformMessage = freeformMessage;
    this.messageType = TypeConstants.MESSAGETYPE.FREEFORM;
  }

  /**
   * Adds a define-message to this info.
   * 
   * @param define -
   *          the new define-message.
   */
  public void addDefine(final DefineMessage define) {

    this.defineList.add(define);
    this.messageType = TypeConstants.MESSAGETYPE.DEFINE;
  }

  /**
   * Adds a list of define-messages to that info.
   * 
   * @param defineList -
   *          the new list.
   */
  public void addDefineList(final LinkedList<DefineMessage> defineList) {

    this.defineList.addAll(defineList);
    this.messageType = TypeConstants.MESSAGETYPE.DEFINE;
  }

  /**
   * @return Returns the define messages.
   */
  public LinkedList<DefineMessage> getDefineList() {

    return this.defineList;
  }

  /**
   * Sets a complete define-list to that info-object.
   * 
   * @param defineList -
   *          the new define-message list.
   */
  public void setDefineList(final LinkedList<DefineMessage> defineList) {

    this.defineList = defineList;
    this.messageType = TypeConstants.MESSAGETYPE.DEFINE;
  }

  /**
   * @return Returns the advice-message of that info-object.
   */
  public AdviceMessage getAdviceMessage() {

    return this.adviceMessage;
  }

  /**
   * Sets a new advice-message to that info object.
   * 
   * @param adviceMessage -
   *          the new advice-message.
   */
  public void setAdviceMessage(final AdviceMessage adviceMessage) {

    this.adviceMessage = adviceMessage;
    this.messageType = TypeConstants.MESSAGETYPE.ADVICE;
  }

  /**
   * @return Returns the info-message of that info- object.
   */
  public InfoMessage getInfoMessage() {

    return this.infoMessage;
  }

  /**
   * Sets a new info-message to that info-object.
   * 
   * @param infoMessage -
   *          the new info-message
   */
  public void setInfoMessage(final InfoMessage infoMessage) {

    this.infoMessage = infoMessage;
    this.messageType = TypeConstants.MESSAGETYPE.INFO;
  }

  /**
   * @return Returns the meta-message of that info-object.
   */
  public MetaMessage getMetaMessage() {

    return this.metaMessage;
  }

  /**
   * Sets a new meta-message to that info-object.
   * 
   * @param metaMessage -
   *          the new meta-message.
   */
  public void setMetaMessage(final MetaMessage metaMessage) {

    this.metaMessage = metaMessage;
    this.messageType = TypeConstants.MESSAGETYPE.META;
  }

  /**
   * @return Returns the delete-message of that info-object.
   */
  public DeleteMessage getDeleteMessage() {

    return this.deleteMessage;
  }

  /**
   * Sets a new delete-message to that info-object.
   * 
   * @param deleteMessage -
   *          the new delet-message.
   */
  public void setDeleteMessage(final DeleteMessage deleteMessage) {

    this.deleteMessage = deleteMessage;
    this.messageType = TypeConstants.MESSAGETYPE.DELETE;
  }

  /**
   * Returns the string-representation for the given clang message. This depends
   * on the type of the message and on the contained messages.
   * 
   * @return (say &lt;clang-string&gt;)
   */
  @Override
  public String toString() {

    final StringBuffer buf = new StringBuffer();

    buf.append("(say ");

    switch (this.messageType) {

      case INIT:
        buf.append("empty");
        break;

      case FREEFORM:
        buf.append("(freeform \"" + this.freeformMessage + "\")");
        break;

      case RULE:
        buf.append(this.ruleMessage.toString());
        break;

      case DELETE:
        buf.append(this.deleteMessage.toString());
        break;

      case DEFINE:
        buf.append("(define");
        for (final DefineMessage dm : this.defineList) {
          buf.append(" " + dm.toString());
        }
        buf.append(")");
        break;

      case META:
        buf.append(this.metaMessage.toString());
        break;

      case ADVICE:
        buf.append(this.adviceMessage.toString());
        break;

      case INFO:
        buf.append(this.infoMessage.toString());
        break;
    }

    buf.append(")");
    return buf.toString();
  }

}
